import logging

from django.db.models import Q
from django.shortcuts import render
from rest_framework.generics import ListAPIView, RetrieveAPIView
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
from rest_framework.views import APIView

from list.models import Course,CourseExpire
from list.serializers import CourseSerializer,CourseDetailSerializer

logger = logging.getLogger('django')


# Create your views here.
class CoursePage(PageNumberPagination):
    # 默认每页显示数量
    page_size = 10

    # 每页最大数量的参数名
    page_size_query_param = 'page_size'

    # 每页最大数量限制
    max_page_size = 50

    def get_paginated_response(self, data):
        return Response({
            "code": 1,
            "message": "SUCCESS",
            "data": {
                'count': self.page.paginator.count,  # 总数量
                'next': self.get_next_link(),  # 下一页的连接
                'previous': self.get_previous_link(),  # 上一页的连接
                'results': data  # 当前页的数据
            }

        })


class CourseListView(ListAPIView):
    """
    http://127.0.0.1:8000/api/courses/?nav_name=免费课
    """
    serializer_class = CourseSerializer
    pagination_class = CoursePage

    def get_queryset(self):
        """
        重写查询方法
        :return: 根据导航名称筛选后的课程查询集
        """

        # 获取查询参数重的导航名称
        nav_name = self.request.query_params.get("nav_name", "")
        category_id = self.request.query_params.get("categoryId", "")
        sorted_num = self.request.query_params.get('sorted_num','')
        price_range = self.request.query_params.get('price_range','')
        # 关键字：但也会出现关键字携带空格的情况:头尾去除
        keyword = self.request.query_params.get('keyword','').strip()

        logger.info(f"正在查询导航分类[{nav_name}],课程分类[{category_id}]下的课程信息,按照{sorted_num}排序")

        #
        # if not nav_name:
        #     logger.info("未提供导航名称参数,返回空数据")
        #     return Course.objects.none()

        try:

            # 构建基础数据
            query_set = Course.objects.filter(status=1)

            # 根据导航名称过滤
            if nav_name:
                logger.info(f"正在根据导航分类[{nav_name}过滤")
                query_set = query_set.filter(nav_relations__nav_category__name=nav_name)

            # 根据分类ID过滤
            if category_id and category_id != '0':
                logger.info(f"正在根据课程分类[{category_id}]过滤")
                query_set = query_set.filter(categories__id=category_id)


            # 按照价格区间查询 1.免费2.付费-->字段是course_type
            if price_range == '1':
                query_set = query_set.filter(course_type=1)
            if price_range == '2':
                query_set = query_set.filter(course_type=2)


            # 关键字查询
            if keyword:
                query_set = query_set.filter(Q(name__icontains=keyword) | Q(teacher__name__icontains=keyword) | Q(brief__icontains=keyword))



            # 如果没有任何的过滤参数
            if not nav_name and not category_id and not price_range and not keyword:
                logger.info("未提供任何过滤条件,返回空数据")
                return Course.objects.none()


            # 按照第二排的排序方式过滤：最新是更新时间-->最热是学习人数-->价格是市场价-->全部是不传返回空
            order_field = '-created_time'
            if sorted_num:
                if sorted_num == '1':
                    order_field = '-pub_date'
                    logger.info("正在按照最新排序")
                if sorted_num == '2':
                    order_field = '-students'
                    logger.info("正在按照最热排序")
                if sorted_num == '3':
                    order_field = 'price'
                    logger.info("正在按照价格排序")


            # 优化查询
            query_set = query_set.select_related('teacher').order_by(order_field).distinct()

            course_count = query_set.count()
            logger.info(f"查询到导航分类{nav_name}下的课程数量:{course_count}")

            return query_set

        except Exception as e:
            logger.error(f"查询课程列表发生异常:{str(e)}")
            return Course.objects.none()










# 开始定以一个新的视图：因为是展示详情，所以正好有一个retrieve方法是详情方法，所以我们可以直接在这个方法中返回详情数据
class CourseDetailView(RetrieveAPIView):

    # 要的是未删除的，课程已经上线的
    queryset = Course.objects.filter(is_deleted=False,status=1)
    serializer_class = CourseDetailSerializer   # 因为前面定义的一连串关系，这里的序列化什么都能显示

    # 但仔细思考一下：这个的返回数据方式就是简单的把data里的东西进行返回，但我们想要的还是固定格式(code,msg)
    # 所以，我们需要重写这个方法，返回我们想要的数据格式
    # 点两层
    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        # 直接修改Response：
        return Response({
            'code':1,
            'message':'success',
            'data':serializer.data
        })





# 课程有效期
class CourseExpireAPIView(APIView):

    def get(self, request, *args, **kwargs):
        """
        请求参数:
            1:?course_ids=1,2,3,4  ?course_ids=1
        返回值:包括课程ID---》价格 ,有效期
        """
        try:

            # 从请求获取参数 1,2,3==>[1,2,3]
            course_ids = request.query_params.get("course_ids")
            logger.info(f"正在获取课程:{course_ids}的课程有效期信息")
            if not course_ids:
                return Response({
                    "code": 0,
                    "message": "参数错误:请提供课程ID"
                })
            course_id_list = [int(id) for id in course_ids.split(",")]
            logger.info(f"正在获取课程:{course_id_list}的课程有效期信息")

            # [1,2,3]
            if not course_id_list:
                return Response({
                    "code": 0,
                    "message": "格式错误"
                })

            # 查询购物车中的课程id的部分信息
            coures = Course.objects.filter(
                id__in=course_id_list,
                is_deleted=False,
                status=1
            ).values("id", "name", "price")
            logger.info(f"查询到课程:{coures}")

            # 构建一个以课程ID为字符串形式的课程字典
            # 该字典推导式遍历课程列表（coures），将每个课程的ID转换为字符串形式作为字典的键，课程对象作为值
            # 这样的设计便于后续通过课程ID快速查找和访问课程信息
            course_dict = {str(course['id']): course for course in coures}
            logger.info(f"课程:{course_dict}")




            # 查询有 有效期的课程
            expire_list = CourseExpire.objects.filter(
                course_id__in=course_id_list
            )
            logger.info(f"查询到课程有效期:{expire_list}")

            # 初始化最终数据的字典
            course_data = {}
            # [1,2,3]

            # 循环有 有效期的课程id列表
            for expire in expire_list:
                course_id = str(expire.course_id)
                logger.info(f"正在处理课程:{course_id}")
                logger.info(course_data)

                # 如果这个课程还没有出现到course_data结果字典中, 初始化最外层的数据结构
                if course_id not in course_data:
                    course_data[course_id] = {
                        'name': expire.course.name,
                        "expire_list": []
                    }

                course_data[course_id]['expire_list'].append(
                    {
                        'expire_time': expire.expire_time,
                        'expire_text': f"{expire.expire_time}天" if expire.expire_time > 0 else "永久有效",
                        "price": float(expire.price)
                    }
                )
                logger.info(course_data)

            # 循环的这是购物车中的课程信息，如果没有找到对应的有效期信息，则添加默认值
            for course_id, course_info in course_dict.items():
                logger.info(course_id)
                logger.info(course_info)

                # course_data他是所有有课程信息的字典返回结果，如果course_id是来自于购物车中的id
                # 如果购物车中的id不存在于有购物车id列表中，那就给他设置默认值，返回格式和上面一样
                if course_id not in course_data:
                    logger.info(f"加默认值:{course_id}")
                    course_data[course_id] = {
                        'name': course_info['name'],  # 直接取上面定义好的字典 的key取小value了
                        'expire_list': [
                            {
                                'expire_time': 0,
                                'expire_text': "永久有效",
                                'price': float(course_info['price'])
                            }
                        ]
                    }
                    # 和这个返回格式是一样的
                    # if course_id not in course_data:
                    #     course_data[course_id] = {
                    #         'name': expire.course.name,
                    #         "expire_list": []
                    #     }
                    #
                    # course_data[course_id]['expire_list'].append(
                    #     {
                    #         'expire_time': expire.expire_time,
                    #         'expire_text': f"{expire.expire_time}天" if expire.expire_time > 0 else "永久有效",
                    #         "price": float(expire.price)
                    #     }
                    # )
                    # logger.info(course_data)

            # 返回结果
            return Response({
                "code": 1,
                "message": "SUCCESS",
                "data": course_data
            })


        except Exception as e:
            logger.error(f"获取课程有效期信息发生异常:{str(e)}")
            return Response({
                "code": 0,
                "message": f"获取课程有效期信息失败:{str(e)}"
            })